/**
 * OSAmI: Open Source Ambient Intelligence
 * Copyright (C) 2010 Bull S.A.S.
 * Contact: osami-general@osami-commons.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */

package org.osami.gateway.identity.naive.internal;

import org.osami.gateway.identity.Identity;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static org.osami.gateway.identity.Identity.State.*;

/**
 * Created by IntelliJ IDEA.
 * User: guillaume
 * Date: 29 juil. 2010
 * Time: 10:51:45
 * To change this template use File | Settings | File Templates.
 */
public class DefaultIdentity implements Identity {

    /**
     * Underlying storage (contains just the properties of this Identity).
     */
    private Map<String, Object> properties = new HashMap<String, Object>();

    /**
     * The parent Identity (may be null).
     */
    private DefaultIdentity parent;

    /**
     * This Identity's childs (may be empty, but not null).
     */
    private Set<DefaultIdentity> children = new HashSet<DefaultIdentity>();

    /**
     * The identifier that is bound to this Identity (may be null).
     */
    private String boundIdentifier;

    /**
     * Unique Identity ID.
     */
    private String id;

    /**
     * Creation timestamp.
     */
    private Date creationDate;

    private FileWriter writer;

    public DefaultIdentity(String id) {
        this.id = id;
        this.creationDate = new Date();

        this.writer = null;
        try {
            writer = new FileWriter("NaiveIdentityManagerOutput.txt", true);
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public String getName() {
        return (String) properties.get(FRIENDLY_NAME);
    }

    public void setName(String name) {
        assert (name != null) : "Identity name cannot be null";
        this.properties.put(FRIENDLY_NAME, name);
    }

    public String getBoundIdentifier() {
        return boundIdentifier;
    }

    public void setBoundIdentifier(String boundIdentifier) {
        this.boundIdentifier = boundIdentifier;
    }

    public String getIdentityID() {
        return id;
    }

    public Map<String, Object> getProperties() {
        return new HashMap<String, Object>(properties);
    }

    public Map<String, Object> getMergedProperties() {
        Map<String, Object> merged = new HashMap<String, Object>();
        if (parent != null) {
            merged.putAll(parent.getProperties());
        }
        // Overrides properties with the one from this Identity
        merged.putAll(properties);
        return merged;
    }

    public State getState() {
        return (boundIdentifier == null) ? UNBOUND : BOUND;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public Identity getParent() {
        return parent;
    }

    public void setParent(DefaultIdentity parent) {
        this.parent = parent;
        parent.getChildren().add(this);
    }

    public Set<DefaultIdentity> getChildren() {
        return children;
    }

    public void addProperty(String name, Object value) {
        assert (name != null) : "Property name cannot be null";
        this.properties.put(name, value);

        // XXX Keep in sync with CreateIdentityOperation !
        if (writer != null) {
            try {
                writer.write("/" + getIdentityID() + "/add?property-name=" + name + "&property-value=" + value);
                writer.flush();
            }
            catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    public void changeProperty(String name, Object value) {
        assert (name != null) : "Property name cannot be null";
        this.properties.put(name, value);

        // XXX Keep in sync with CreateIdentityOperation !
        if (writer != null) {
            try {
                writer.write("/" + getIdentityID() + "/change?" + name + "?new-value=" + value + "\n");
                writer.flush();
            }
            catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    public void putProperties(Map<String, Object> properties) {
        if (properties != null) {
            for (String name : properties.keySet()) {
                Object value = properties.get(name);
                changeProperty(name, value);
            }
        }
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append("[DefaultIdentity: ");

        sb.append("id:'").append(id).append("' ");
        sb.append("boundIdentifier:'").append(boundIdentifier).append("' ");
        sb.append("creationDate:'").append(creationDate).append("' ");
        sb.append("properties:'").append(getMergedProperties()).append("' ");
        if (parent != null) {
            sb.append("parent:'").append(parent.getIdentityID()).append("' ");
        }

        sb.append("children:{");
        for (Identity id : children) {
            sb.append(id.getIdentityID());
            sb.append(" ");
        }
        sb.append("}");

        sb.append("]");
        return sb.toString();
    }

}
